#! /bin/sh

usage () {
  print_info "@common import script"
  print_info "@support dmp and txt file only!"
  print_info "@author: hippo"
  print_info "@email: binzero$ymail$com"
  print_info ""
  return 0
}

# ----------------------------------------------------------------------
# Function:  print_info (); print_error ()
# Description:  print message to stdout
# Parameters:
#  $message -something info
#
print_info () {
  echo `date +"%D %H:%M:%S"` Inf: "$1"
  return 0
}

print_error () {
  echo `date +"%D %H:%M:%S"` Err: "$1"
  return 0
}

# ----------------------------------------------------------------------
# Function: import_file ()
# Description: Import the specified file
# Parameters:
#  $file_name - specify the file name, ".txt" or ".dmp" files are allowed.
#  $file_symbol - file symbol which identify the file or control file
#
import_file () {
  if [ "$#" -ne 2 ] ; then
    print_error "import_file() argc error!"
    return -1
  fi
  print_info "file:importing..."
  # import the txt file
  if echo $1 | grep -iq "\.txt$"
  then
    local ctl_file=$2.CTL
    if [ ! -f ctl/$ctl_file ] ; then
      print_info "Control file: $ctl_file not found! exit"
      return -1
    fi
    sqlldr $DB_CONN ctl/$ctl_file $LOGDIR/$LOG_DATE.$1.log $BADDIR/$LOG_DATE.$1.bad $1 > /dev/null
    local rows_success=`grep "successfully loaded" $LOGDIR/$LOG_DATE.$1.log | awk '{print $1}'`
    local rows_error=`grep "due to data errors" $LOGDIR/$LOG_DATE.$1.log | awk '{print $1}'`
    local ret=`[ $rows_error -eq 0 ] && echo 0 || echo 1`
    local elapsed_time=`grep "Elapsed time" $LOGDIR/$LOG_DATE.$1.log | awk '{print $4}' | awk -F: '{print $1*3600+$2*60+$3}'`
  # import the dmp file
  elif echo $1 | grep -iq "\.dmp$" 
  then
    local fromuser=`awk '$1~/'"$2"'/{print $2}' < hippo_symbol.lst`
    local touser=`awk '$1~/'"$2"'/{print $3}' < hippo_symbol.lst`
    local tables=`awk '$1~/'"$2"'/{print $4}' < hippo_symbol.lst`
    #print_info "fromuser=$fromuser touser=$touser tables=$tables"
    local elapsed_time=`/usr/bin/time -p imp $DB_CONN file=$1 ignore=y indexes=n statistics=none constraints=n grants=n compile=n\
            fromuser="$fromuser" touser="$touser" tables="($tables)" log=$LOGDIR/$LOG_DATE.$1.log 2>&1 | awk '$1~/[Rr]eal/{print $2}'`
    local rows_success=`grep "rows imported" $LOGDIR/$LOG_DATE.$1.log | awk '{sum += $6}END{print sum}'`
    local rows_error=
    grep -qE "ORA-|IMP-" $LOGDIR/$LOG_DATE.$1.log
    [ $? -eq 0 ] && ret=1 || ret=0
  fi
  # record the log into table
  sqlplus -S $DB_CONN << EOF 
  set feedback off
  insert into hippo_imp_log (
    file_date, file_symbol,
    package_name, file_name,
    rows_success, rows_error,
    time_interval, status)
  values (
     to_date('$acc_date','yyyymmdd'),'$2',
     '$NEW_ZFILE', '$1',
     '$rows_success', '$rows_error',
     interval '${elapsed_time:-0}' second, '$ret');
  commit;
  exit;
EOF
  return 0
}

# ----------------------------------------------------------------------
# Function:   upd_acc_date ()
# Description:  update the accperiod's BEG_DATE and END_DATE 
# Parameters:  none
#
get_date_range () {
  local beg_end_tmp=`sqlplus -S $DB_CONN << EOF
    set feedback off
    set head off
    set pagesize 0
    select to_char(start_date,'yyyymmdd'), to_char(end_date, 'yyyymmdd')
      from hippo_imp_range
     where imp_enable = 'Y'
       and rownum = 1;
    exit;
EOF
`
  BEG_DATE=`echo "$beg_end_tmp" | awk '{print $1}'`
  END_DATE=`echo "$beg_end_tmp" | awk '{print $2}'`
  return 0
}

# ----------------------------------------------------------------------
# Function:  check_date ()
# Description:  
# Parameters: $date format"YYYYMMDD" 
check_date () {
  if [ `echo $1 | grep -v "^[0-9]\{8\}$"` ] ; then
    print_info "$1 is an illegal date"
    return -1
  fi
  local year=`echo $1 | cut -c1-4`
  local month=`echo $1 | cut -c5-6`
  local day=`echo $1 | cut -c7-8`
  if [ "$year" -lt 1970 -o "$year" -gt 9999 ];then
    print_info "$1 is an illegal date,year=$year"
    return -1
  fi
  if [ "$month" -lt 1 -o "$month" -gt 12 ];then
    print_info "$1 is an illegal date,month=$year"
    return -1
  fi
  if [ "$day" -lt 1 -o "$day" -gt 31 ];then
    print_info "$1 is an illegal date,day=$day"
    return -1
  fi
  return 0
}

# ----------------------------------------------------------------------
# Function:  clean_system ()
# Description:  delete logs,bad files,temp files, etc.
# Parameters:  none
clean_system () {
  find ./ \( -name "*.log" -o -name "*.bad" \) -mtime +30 -exec rm -f {} \;
  for tmpfile in $( ls | grep -iE "\.txt$|\.dmp$" ); do
    rm -f "$tmpfile"
  done
  print_info "System have been cleaned!"
  return 0
}

# ----------------------------------------------------------------------
# Function:  pkg_import_finish ()
# Description: when finished a package,invoke this function
# Parameters:  none
pkg_import_finish () {
  print_info "Invoke the proc hippo_imp.finish(pkg_name)!"
  sqlplus -S $DB_CONN << EOF
    set feedback off
    set head off
    begin
      hippo_imp.finish('$NEW_ZFILE');
    end;
    /
    exit;
EOF
  return 0
}

# ----------------------------------------------------------------------
# Function:  archive_file ()
# Description:  backup the file
# Parameters:  $package_name
#              $status
archive_file () {
  local dist_file="$1"
  local status=${2-0}
  local n=0
  while [ -f "$BACKDIR/$dist_file" ] ; do
    print_info "File: $BACKDIR/$dist_file is exist!"
    ((n+=1))
    local dist_file="${1%.tar.Z}"".$n.tar.Z"
  done
  NEW_ZFILE=$dist_file # update the NEW_ZFILE
  mv "$FILEDIR/$1" "$BACKDIR/$dist_file"
  sqlplus -S $DB_CONN << EOF 
  set feedback off
  delete from hippo_imp_archive where package_name = '$NEW_ZFILE';
  insert into hippo_imp_archive (file_date,package_name,file_size,status) values (to_date('$acc_date','yyyymmdd'),'$NEW_ZFILE','$file_size','$status');
  commit;
  exit;
EOF
  print_info "Archive $1 to $dist_file done!"
  return 0
}

# ----------------------------------------------------------------------
# Function:  sync_everthing ()
# Description:  synchronous the list from the db every half an hour;
# Parameters:  none  
sync_everthing () {
    sqlplus -S $DB_CONN << EOF > /dev/null
      set feedback off
      set head off
      set linesize 999
      set pagesize 0
      set trimspool on
      spool hippo_symbol.lst
      select file_symbol || ' ' || fromuser || ' ' || touser || ' ' || contain_tables
        from hippo_imp_control where imp_enable = 'Y';
      spool off
      spool hippo_archive.lst
      select package_name || ' ' || status from hippo_imp_archive;
      spool off
      exit;
EOF
  if [ `ls $BACKDIR | wc -l` -ne 0 ]; then
    for zfile_tmp in $BACKDIR/*; do
      local pkg_name=`basename $zfile_tmp`
      local line_str=`grep "$pkg_name" hippo_archive.lst`
      # if pkg_name is not resided in db,delete it;
      if [ -z "$line_str" ] ; then
	rm -f $zfile_tmp
        print_info "$pkg_name deleted!"
      else
        # if pkg_name's status = 1 ,move it;
        if [ `echo $line_str | awk '{print $2}'` -eq 1 ] ; then
          print_info "$pkg_name need import again!"
          if [ -e $FILEDIR/$pkg_name ] ; then
            print_info "File:$FILEDIR/$pkg_name is already exist! move pass!"
	    continue
	  fi
          mv $zfile_tmp $FILEDIR
        fi
      fi
    done 
  fi
  return 0
}

# ----------------------------------------------------------------------
# main
# ----------------------------------------------------------------------

print_info "********************************************************************"
usage
# load configure file 
. ./hippo_imp_cfg
#[ -d $WORKDIR ] || mkdir $WORKDIR
[ -d $LOGDIR ] || mkdir $LOGDIR
[ -d $BADDIR ] || mkdir $BADDIR
[ -d $BACKDIR ] || mkdir $BACKDIR
cd $WORKDIR

# save some info to log
print_info "~~~~~~~~~~~env info~~~~~~~~~~~"
print_info "ORACLE_HOME=$ORACLE_HOME"
print_info "FILEDIR=$FILEDIR"
print_info "WORKDIR=$WORKDIR"
print_info "LOGDIR=$LOGDIR"
print_info "BADDIR=$BADDIR"
print_info "BACKDIR=$BACKDIR"
print_info "LOCKFILE=$LOCKFILE"
print_info "pkg detection interval=$FREQ s"
print_info "pkg date position=$DATE_POSITION"
print_info "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

# Prevent this daemon process concurrent running.
if [ ! -f "$LOCKFILE" ]; then
  echo "$$" > $LOCKFILE
  print_info "$0 daemon process started!"
else
  lock_pid=`cat $LOCKFILE`
  if ps -ef | grep "$0" | grep "$lock_pid" | grep -qv grep ; then
    print_info "An another daemon process is running now,exit!"
    exit 0;
  else
    echo "$$" > $LOCKFILE
    print_info "$0 daemon process started!"
  fi
fi

# infinite loops
while :;do
  # if the file directory is not empty,update the date range.
  if [ `ls $FILEDIR | wc -c` -ne 0 ] ; then
    echo
    print_info "FILEDIR have packages need to be handled."
    print_info "synchronizing hippo_symbol.lst,hippo_archive.lst..."
    sync_everthing
    if tnsping "$DB_IDENTIFIER" | grep -q "OK" ; then
      BEG_DATE=  # initialize
      END_DATE=
      if get_date_range ; then
        if [ -z "$BEG_DATE" -o -z "$END_DATE" ]; then
          print_info "Obtain date range failed,main thread will sleep half an hour."
          sleep 1800
          continue
        else
          print_info "Obtain date range successed,[$BEG_DATE,$END_DATE] ."
	  clean_system
        fi
      else
        print_error "Something happened when obtain date range! main thread will sleep an hour."
        sleep 3600
        continue
      fi
    else
      print_error "Can not contact database $DB_IDENTIFIER,please check the network."
      print_info "The main thread will sleep an hour."
      sleep 3600
      continue
    fi
  else
    sleep $FREQ
    f_tmp=`find . -name "hippo_symbol.lst" -mmin -10`
    if [ -z "$f_tmp" ] ; then
       sync_everthing
    fi
    continue
  fi
  # process all packages
  for zfile in $(ls $FILEDIR/* | sort ); do
    NEW_ZFILE=`basename $zfile`
    LOG_DATE=`date +"%y%m%d%H%M"`
    print_info "{ $NEW_ZFILE }"
    # print_info "Detecting the package size,wait until it is not increase any more."
    file_size=0  #initialize the file_size.
    file_size_tmp=0
    while :; do
      file_size=`ls -l $zfile | awk '{print $5}'`
      if [ $file_size_tmp -eq $file_size ]; then break; fi
      file_size_tmp=$file_size
      print_info "pkg:receiving..." 
      sleep 60
    done
    acc_date=`basename $zfile | awk -F[_\.] '{print $'${DATE_POSITION}'}'`
    if ! check_date $acc_date ; then
      print_error "pkg:date format error !archive it!s=9"
      acc_date= # if date is illegal,it can't store in db;
      archive_file "$NEW_ZFILE" "9"
      continue
    fi
    if [ $acc_date -lt $BEG_DATE -o $acc_date -gt $END_DATE ]; then
      print_error "pkg:date $acc_date not in [$BEG_DATE,$END_DATE].archive it!s=7"
      archive_file "$NEW_ZFILE" "7"
      continue
    fi
    print_info "pkg:decompressing ..."
    zcat $zfile | tar -xvf -
    if [ "$?" -ne 0 ]; then
      print_error "pkg:broken!cant decompress,archive it!s=8"
      archive_file "$NEW_ZFILE" "8"
      continue
    fi
    # archive package and update NEW_ZFILE ---***---;
    archive_file "$NEW_ZFILE"
    #** warning:after archive,new_zfile may have been updated;
    # if file is compressed ,uncompressed it;
    for xfile in $( ls | grep -iE "\.Z$" ); do
      print_info "$xfile need uncompress first!"
      uncompress $xfile
    done
    # start import the dmp or txt files;
    for file in $( ls | grep -iE "\.txt$|\.dmp$" ); do
      print_info "[ $file ]"
      # get the file symbol
      file_symbol= #init
      for i in $(cat hippo_symbol.lst | awk '{print $1}'); do
        if echo ${file%.*} | grep -qi $i ; then
          print_info "file:cfg=`grep $i hippo_symbol.lst`"
          file_symbol=$i
          break;
        fi
      done
      if [ -z "$file_symbol" ] ; then
        print_info "file:cfg=none,ignore!"
      else
        import_file "$file" "$file_symbol" # NEW_ZFILE will also be used in import_file()
      fi
      rm -f $file
      print_info "file:process done! deleted!"
    done
    pkg_import_finish # record the $NEW_ZFILE
  done
  print_info "There are no more available packages!"
  sleep 60
done
